#!/bin/bash

# =============================================================================
# 应用更新脚本 - 用于后续代码更新
# =============================================================================

set -e

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'

log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; }
log_warning() { echo -e "${YELLOW}[WARNING]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }

# 项目配置
PROJECT_DIR="/var/www/memebot"
BACKUP_DIR="/home/$USER/memebot_backups"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)

log_info "开始应用更新流程..."

# 显示使用说明
show_usage() {
    echo -e "\n${BLUE}=== 应用更新脚本使用说明 ===${NC}"
    echo "此脚本支持多种更新方式："
    echo ""
    echo "1. 从本地上传更新 (推荐):"
    echo "   # 在本地执行:"
    echo "   rsync -avz --exclude node_modules --exclude .env --exclude .git /path/to/local/project/ user@server:/tmp/memebot_update/"
    echo "   # 在服务器执行:"
    echo "   ./scripts/update-app.sh local"
    echo ""
    echo "2. 从Git仓库更新:"
    echo "   ./scripts/update-app.sh git [branch_name]"
    echo ""
    echo "3. 手动文件替换后更新:"
    echo "   ./scripts/update-app.sh manual"
    echo ""
    echo "4. 快速重启 (不更新代码):"
    echo "   ./scripts/update-app.sh restart"
    echo ""
    echo "5. 修复依赖和构建问题:"
    echo "   ./scripts/update-app.sh fix"
    echo ""
    echo "参数说明:"
    echo "  local   - 从 /tmp/memebot_update/ 目录更新"
    echo "  git     - 从Git仓库更新 (需要先配置仓库)"
    echo "  manual  - 手动替换文件后的更新流程"
    echo "  restart - 仅重启应用，不更新代码"
    echo "  fix     - 修复依赖问题并重新构建"
    echo -e "${BLUE}=================================${NC}\n"
}

# 检查参数
check_params() {
    if [ $# -eq 0 ]; then
        show_usage
        exit 1
    fi
    
    UPDATE_METHOD=$1
    GIT_BRANCH=${2:-main}
}

# 创建备份
create_backup() {
    log_info "创建当前版本备份..."
    
    mkdir -p $BACKUP_DIR
    
    # 备份整个项目目录
    tar -czf $BACKUP_DIR/memebot_backup_$TIMESTAMP.tar.gz -C /var/www memebot
    
    # 备份数据库
    if command -v pg_dump &> /dev/null; then
        source $PROJECT_DIR/.env 2>/dev/null || true
        if [ -n "$DATABASE_URL" ]; then
            pg_dump "$DATABASE_URL" > $BACKUP_DIR/database_backup_$TIMESTAMP.sql 2>/dev/null || log_warning "数据库备份失败"
        fi
    fi
    
    # 保留最近10个备份
    cd $BACKUP_DIR
    ls -t memebot_backup_*.tar.gz 2>/dev/null | tail -n +11 | xargs rm -f 2>/dev/null || true
    ls -t database_backup_*.sql 2>/dev/null | tail -n +11 | xargs rm -f 2>/dev/null || true
    
    log_success "备份完成: $BACKUP_DIR/memebot_backup_$TIMESTAMP.tar.gz"
}

# 停止应用
stop_application() {
    log_info "停止应用服务..."
    
    if pm2 describe memebot-trading > /dev/null 2>&1; then
        pm2 stop memebot-trading
        log_success "应用已停止"
    else
        log_info "应用未运行"
    fi
}

# 从本地更新
update_from_local() {
    log_info "从本地目录更新代码..."
    
    LOCAL_UPDATE_DIR="/tmp/memebot_update"
    
    if [ ! -d "$LOCAL_UPDATE_DIR" ]; then
        log_error "本地更新目录不存在: $LOCAL_UPDATE_DIR"
        log_info "请先上传代码到此目录，例如:"
        echo "  rsync -avz --exclude node_modules /path/to/local/project/ user@server:$LOCAL_UPDATE_DIR/"
        exit 1
    fi
    
    # 检查关键文件
    if [ ! -f "$LOCAL_UPDATE_DIR/package.json" ]; then
        log_error "更新目录中未找到 package.json"
        exit 1
    fi
    
    # 保留重要配置文件
    cp $PROJECT_DIR/.env /tmp/.env.backup 2>/dev/null || true
    cp $PROJECT_DIR/ecosystem.config.js /tmp/ecosystem.config.js.backup 2>/dev/null || true
    
    # 同步代码文件
    rsync -av --exclude=node_modules --exclude=.env --exclude=ecosystem.config.js $LOCAL_UPDATE_DIR/ $PROJECT_DIR/
    
    # 恢复配置文件
    cp /tmp/.env.backup $PROJECT_DIR/.env 2>/dev/null || true
    cp /tmp/ecosystem.config.js.backup $PROJECT_DIR/ecosystem.config.js 2>/dev/null || true
    
    # 清理临时文件
    rm -rf $LOCAL_UPDATE_DIR
    rm -f /tmp/.env.backup /tmp/ecosystem.config.js.backup
    
    log_success "代码更新完成"
}

# 从Git更新
update_from_git() {
    log_info "从Git仓库更新代码..."
    
    cd $PROJECT_DIR
    
    # 检查是否为Git仓库
    if [ ! -d ".git" ]; then
        log_error "项目目录不是Git仓库"
        log_info "如需使用Git更新，请先初始化Git仓库:"
        echo "  cd $PROJECT_DIR"
        echo "  git init"
        echo "  git remote add origin <your-repo-url>"
        exit 1
    fi
    
    # 保存本地更改
    git stash push -m "Auto stash before update $TIMESTAMP" 2>/dev/null || true
    
    # 拉取最新代码
    git fetch origin
    git checkout $GIT_BRANCH
    git pull origin $GIT_BRANCH
    
    log_success "Git代码更新完成"
}

# 手动更新
update_manual() {
    log_info "执行手动更新后的处理流程..."
    log_warning "假设您已经手动替换了需要更新的文件"
}

# 快速重启 (不更新代码)
restart_only() {
    log_info "快速重启应用..."
    
    # 停止应用
    if pm2 describe memebot-trading > /dev/null 2>&1; then
        pm2 restart memebot-trading
        log_success "应用重启完成"
    else
        log_info "应用未运行，正在启动..."
        cd $PROJECT_DIR
        pm2 start ecosystem.config.js
        log_success "应用启动完成"
    fi
    
    # 简单健康检查
    sleep 5
    if pm2 describe memebot-trading > /dev/null 2>&1; then
        log_success "应用运行正常"
        pm2 status
    else
        log_error "应用启动失败"
        pm2 logs memebot-trading --lines 10
    fi
}

# 修复依赖和构建问题
fix_issues() {
    log_info "修复依赖和构建问题..."
    cd $PROJECT_DIR
    
    # 清理并重新安装依赖
    log_info "清理并重新安装依赖..."
    rm -rf node_modules package-lock.json
    npm install
    
    # 处理安全漏洞
    log_info "修复安全漏洞..."
    npm audit fix --force || log_warning "部分安全问题无法自动修复"
    
    # 重新生成Prisma客户端
    log_info "重新生成Prisma客户端..."
    npx prisma generate
    
    # 重新构建
    log_info "重新构建应用..."
    npm run build
    
    log_success "修复完成"
}

# 更新依赖
update_dependencies() {
    log_info "检查并更新依赖..."
    cd $PROJECT_DIR
    
    # 检查package.json是否有变化
    if [ -f "/tmp/package.json.backup" ]; then
        if ! diff package.json /tmp/package.json.backup > /dev/null 2>&1; then
            log_info "package.json有变化，重新安装依赖..."
            rm -rf node_modules package-lock.json
            npm install
        else
            log_info "package.json无变化，跳过依赖安装"
        fi
        rm -f /tmp/package.json.backup
    else
        log_info "安全起见，重新安装依赖..."
        npm install
    fi
}

# 运行数据库迁移
run_database_migration() {
    log_info "检查数据库迁移..."
    cd $PROJECT_DIR
    
    # 生成Prisma客户端
    npx prisma generate
    
    # 推送数据库变更
    npx prisma db push
    
    log_success "数据库迁移完成"
}

# 构建应用
build_application() {
    log_info "构建应用..."
    cd $PROJECT_DIR
    
    # 构建Next.js应用
    npm run build
    
    log_success "应用构建完成"
}

# 启动应用
start_application() {
    log_info "启动应用服务..."
    cd $PROJECT_DIR
    
    # 启动应用
    pm2 start ecosystem.config.js
    
    # 等待启动
    sleep 10
    
    # 检查状态
    if pm2 describe memebot-trading > /dev/null 2>&1; then
        log_success "应用启动成功"
        pm2 status
    else
        log_error "应用启动失败"
        pm2 logs memebot-trading --lines 20
        
        # 尝试回滚
        log_warning "尝试回滚到备份版本..."
        rollback_application
        exit 1
    fi
}

# 健康检查
health_check() {
    log_info "执行健康检查..."
    
    # 等待应用完全启动
    sleep 15
    
    # 检查HTTP响应
    for i in {1..5}; do
        if curl -f -s http://localhost:3000/health > /dev/null 2>&1; then
            log_success "健康检查通过"
            return 0
        fi
        log_info "等待应用启动... ($i/5)"
        sleep 10
    done
    
    log_error "健康检查失败"
    return 1
}

# 回滚应用
rollback_application() {
    log_warning "开始回滚应用..."
    
    # 停止当前应用
    pm2 stop memebot-trading 2>/dev/null || true
    
    # 找到最新的备份
    LATEST_BACKUP=$(ls -t $BACKUP_DIR/memebot_backup_*.tar.gz 2>/dev/null | head -1)
    
    if [ -n "$LATEST_BACKUP" ]; then
        log_info "恢复备份: $LATEST_BACKUP"
        
        # 删除当前目录
        sudo rm -rf $PROJECT_DIR
        
        # 恢复备份
        sudo mkdir -p /var/www
        sudo tar -xzf $LATEST_BACKUP -C /var/www
        sudo chown -R $USER:$USER $PROJECT_DIR
        
        # 启动应用
        cd $PROJECT_DIR
        pm2 start ecosystem.config.js
        
        log_success "回滚完成"
    else
        log_error "未找到备份文件"
    fi
}

# 清理临时文件
cleanup() {
    log_info "清理临时文件..."
    rm -f /tmp/.env.backup /tmp/ecosystem.config.js.backup /tmp/package.json.backup
    rm -rf /tmp/memebot_update
}

# 主函数
main() {
    check_params "$@"
    
    log_info "更新方法: $UPDATE_METHOD"
    
    # 备份package.json用于比较
    cp $PROJECT_DIR/package.json /tmp/package.json.backup 2>/dev/null || true
    
    # 创建备份
    create_backup
    
    # 停止应用
    stop_application
    
    # 根据更新方法执行相应操作
    case $UPDATE_METHOD in
        "local")
            update_from_local
            ;;
        "git")
            update_from_git
            ;;
        "manual")
            update_manual
            ;;
        "restart")
            restart_only
            return 0  # 快速重启不需要执行后续步骤
            ;;
        "fix")
            # 停止应用
            stop_application
            # 修复问题
            fix_issues
            # 启动应用
            start_application
            # 健康检查
            if ! health_check; then
                log_error "修复后应用仍有问题"
                pm2 logs memebot-trading --lines 20
                exit 1
            fi
            log_success "问题修复完成！"
            return 0
            ;;
        *)
            log_error "无效的更新方法: $UPDATE_METHOD"
            show_usage
            exit 1
            ;;
    esac
    
    # 更新依赖
    update_dependencies
    
    # 运行数据库迁移
    run_database_migration
    
    # 构建应用
    build_application
    
    # 启动应用
    start_application
    
    # 健康检查
    if ! health_check; then
        log_error "更新失败，正在回滚..."
        rollback_application
        exit 1
    fi
    
    # 清理
    cleanup
    
    log_success "应用更新完成！"
    log_info "当前版本备份位置: $BACKUP_DIR/memebot_backup_$TIMESTAMP.tar.gz"
    
    # 显示状态
    echo -e "\n${BLUE}=== 应用状态 ===${NC}"
    pm2 status
    echo -e "\n${BLUE}=== 最近日志 ===${NC}"
    pm2 logs memebot-trading --lines 10
}

# 运行主函数
main "$@"
